/**
 * 第1节
 * 本节的目的是迅速的实现一个最精简的语言的功能，让你了解一门计算机语言的骨架。
 * 
 * 知识点：
 * 1.递归下降的方法做词法分析；
 * 2.语义分析中的引用消解（找到函数的定义）；
 * 3.通过遍历AST的方法，执行程序。
 * 
 * 本节采用的语法规则是极其精简的，只能定义函数和调用函数。定义函数的时候，还不能有参数。
 * 
 * EBNF规则：
 * prog = (functionDecl | functionCall)* ;
 * functionDecl: "function" Identifier "(" ")"  functionBody;
 * functionBody : '{' functionCall* '}' ;
 * functionCall : Identifier '(' parameterList? ')' ;
 * parameterList : StringLiteral (',' StringLiteral)* ;
 * 
 * 其他：
 * 系统调用以nl.开始
 * functionCall.name.startsWith("nl.")
 * 
 * 例子中的两个Token数组，需要手工切换后tsc编译，再运行
 * 运行：
 * npm install typescript -g
 * npm i --save-dev @types/node
 * tsc play.ts
 * node play.js
 * 
 */

import {Parser} from './nparser';
import {TokenKind, Token, Tokenizer} from './nscanner';
import {RefResolver} from './nsemantic';
import {Intepretor} from './nintepretor';

// 第1个Token数组，代表了下面这段程序做完词法分析后的结果：
/*
function sayHello(){
    println("Hello World!");
}
sayHello();
*/
let tokenArraySayHello: Token[] = [
    {kind:TokenKind.Keyword,      text:'function'},
    {kind:TokenKind.Identifier,   text:'sayHello'},
    {kind:TokenKind.Seperator,    text:'('},
    {kind:TokenKind.Seperator,    text:')'},
    {kind:TokenKind.Seperator,    text:'{'},
    {kind:TokenKind.Identifier,   text:'nl.println'},
    {kind:TokenKind.Seperator,    text:'('},
    {kind:TokenKind.StringLiteral,text:'Hello World!'},
    {kind:TokenKind.Seperator,    text:')'},
    {kind:TokenKind.Seperator,    text:';'},
    {kind:TokenKind.Seperator,    text:'}'},
    {kind:TokenKind.Identifier,   text:'sayHello'},
    {kind:TokenKind.Seperator,    text:'('},
    {kind:TokenKind.Seperator,    text:')'},
    {kind:TokenKind.Seperator,    text:';'},
    {kind:TokenKind.EOF,          text:''}
];

// 第2个Token数组，代表了下面这段程序做完词法分析后的结果：
/*
function foo(){
    println("in foo...");
}
function bar(){
    println("in bar...");
    foo();
}
bar();
*/
let tokenArrayFooBar: Token[] = [
    {kind:TokenKind.Keyword,      text: 'function' },
    {kind:TokenKind.Identifier,   text: 'foo' },
    {kind:TokenKind.Seperator,    text: '(' },
    {kind:TokenKind.Seperator,    text: ')' },
    {kind:TokenKind.Seperator,    text: '{' },
    {kind:TokenKind.Identifier,   text: 'nl.println' },
    {kind:TokenKind.Seperator,    text: '(' },
    {kind:TokenKind.StringLiteral,text: 'in foo...' },
    {kind:TokenKind.Seperator,    text: ')' },
    {kind:TokenKind.Seperator,    text: ';' },
    {kind:TokenKind.Seperator,    text: '}' },
    {kind:TokenKind.Keyword,      text: 'function' },
    {kind:TokenKind.Identifier,   text: 'bar' },
    {kind:TokenKind.Seperator,    text: '(' },
    {kind:TokenKind.Seperator,    text: ')' },
    {kind:TokenKind.Seperator,    text: '{' },
    {kind:TokenKind.Identifier,   text: 'nl.println' },
    {kind:TokenKind.Seperator,    text: '(' },
    {kind:TokenKind.StringLiteral,text: 'in bar...' },
    {kind:TokenKind.Seperator,    text: ')' },
    {kind:TokenKind.Seperator,    text: ';' },
    {kind:TokenKind.Identifier,   text: 'foo' },
    {kind:TokenKind.Seperator,    text: '(' },
    {kind:TokenKind.Seperator,    text: ')' },
    {kind:TokenKind.Seperator,    text: ';' },
    {kind:TokenKind.Seperator,    text: '}' },
    {kind:TokenKind.Identifier,   text: 'bar' },
    {kind:TokenKind.Seperator,    text: '(' },
    {kind:TokenKind.Seperator,    text: ')' },
    {kind:TokenKind.Seperator,    text: ';' },
    {kind:TokenKind.EOF,          text:''}
];

/////////////////////////////////////////////////////////////////////////
// 主程序

function compileAndRun(){
    //词法分析
    //let tokenizer = new Tokenizer(tokenArraySayHello);
    let tokenizer = new Tokenizer(tokenArrayFooBar);
    console.log("\n程序所使用的Token:");
    for (let token of tokenArrayFooBar){
        console.log(token);
    }

    //语法分析
    let prog = new Parser(tokenizer).parseProg();
    console.log("\n语法分析后的AST:");
    prog.dump("");

    //语义分析
    new RefResolver().visitProg(prog);
    console.log("\n语义分析后的AST，注意自定义函数的调用已被消解:");
    prog.dump("");

    //运行程序
    console.log("\n运行当前的程序:");
    let retVal = new Intepretor().visitProg(prog);
    console.log("程序返回值：" + retVal);
}

//运行示例
compileAndRun();
